#include "sct/decode/audiodec.h"

namespace sct
{
void CAudioDec::init()
{
	switch(mCodecType)
	{
	case CT_AAC:
	{
		mCodec = avcodec_find_decoder(AV_CODEC_ID_AAC);
		break;
	}

	default:
	{
		SCT_LOGD();
		break;
	}
	}

	if(NULL == mCodec)
	{
		SCT_LOGD("audio dec not found");
		return;
	}

	SCT_LOGD("audio dec name:%s", mCodec->long_name);
	mCodecCtx = avcodec_alloc_context3(mCodec);

	int ret;
	ret = avcodec_open2(mCodecCtx, mCodec, NULL);
	if(ret<0)
	{
		SCT_LOGD("audio ctx open failed:%d", ret);
	}

	mFrame = av_frame_alloc();
	av_init_packet(&mPkt);
}

void CAudioDec::decode(const void * d, const int len, const int64_t pts)
{
	mPkt.data = (uint8_t*)d;
    mPkt.size = len;
    mPkt.pts = pts;

	int ret = 0;
	while(1)
	{
		if(mPkt.size <= 0) break;

		int nDecode;
		nDecode = avcodec_decode_audio4(mCodecCtx, mFrame, &ret, &mPkt);
		if(nDecode < 0)
		{
			SCT_LOGD("audio decode error");
			break;
		}

		mPkt.data += nDecode;
		mPkt.size -= nDecode;

		if(ret)
		{
			if(!mSwr)
			{
				mSwr = swr_alloc();
				mSwr = swr_alloc_set_opts(mSwr,
						AV_CH_LAYOUT_STEREO,
						AV_SAMPLE_FMT_S16,
                        mFrame->sample_rate,
						mFrame->channel_layout,
						(AVSampleFormat)(mFrame->format),
						mFrame->sample_rate,
						0,
						NULL);
				swr_init(mSwr);
			}

			if(mSize != mFrame->nb_samples*2*2)
			{
				mSize = mFrame->nb_samples*2*2;

				SCT_DELETE_ARRAY(mData);
				mData = new uint8_t[mSize];
			}

			swr_convert(mSwr,
					&mData, mFrame->nb_samples,
					(const uint8_t**)mFrame->data, mFrame->nb_samples);

			CBlockInfo info;
			info.nb_samples = mFrame->nb_samples;
            info.sample_rate = mFrame->sample_rate;
            info.pts = mFrame->pkt_pts;

			mCallback->onGenData(this, mData, mSize, info);
		}
		else
		{
			SCT_LOGD("not output");
			break;
		}
	}
}

CAudioDec::CAudioDec(const CodecType codecType):CDecodeInterface(codecType),
		mCodecCtx(NULL),
		mCodec(NULL),
		mFrame(NULL),
		mSwr(NULL),
		mData(NULL),
		mSize(0)
{
}

CAudioDec::~CAudioDec()
{
	if(mData)
	{
		SCT_DELETE_ARRAY(mData);
	}

	if(mSwr)
	{
		swr_free(&mSwr);
		mSwr = NULL;
	}

	if(mCodecCtx)
	{
		avcodec_close(mCodecCtx);
		av_free(mCodecCtx);
		mCodecCtx = NULL;
	}

	if(mFrame)
	{
		av_frame_free(&mFrame);
		mFrame=NULL;
	}
}
}
